Online-Academy
Look, Read, Understand, Apply

WildCard Erasure Inheritance Collections

class Pair<K, V> {
    K key;
    V value;
}

When an object is created, actual types are supplied:

Pair<String, Integer> p = new Pair<>();

Bounded Wildcards (extends / super)

A wildcard ? represents an unknown type.
? extends
Used when a collection can contain a particular type or its subclasses.
List<? extends Number> list;
It can refer to:    
List<Integer>
List<Double>

It is mainly useful when reading data.
? super
Used when a collection can contain a particular type or its superclasses.

List<? super Integer> list;
List<Integer>
List<Number>
List<Object>

It is mainly useful when adding data.

Easy rule:
extends --> read
super --> write
Type Erasure and Heap Pollution
Type Erasure
Java implements generics mainly through type erasure. Generic type information is removed or replaced with appropriate casts during compilation.

List<String>

is essentially treated as a List at runtime. This maintains compatibility with older Java code.

Heap Pollution: Heap pollution occurs when a variable of a parameterized type refers to an object that does not have the expected parameterized type. List<String> list = new ArrayList<>(); Using raw types or unsafe operations can cause heap pollution and potentially produce ClassCastException.
Restrictions and Limitations of Generics
Some important limitations are:

Cannot use primitive types directly:
List<int>   Invalid
List<Integer>  Valid

Cannot create an object directly using a type parameter:
new T();  Invalid
Cannot create generic arrays easily:
T[] arr;  Declaration possible, direct creation is restricted

Cannot use instanceof with a parameterized type:

obj instanceof List  Invalid

Static members cannot use a class's type parameter.
Generic type information is generally unavailable at runtime because of type erasure.
Inheritance Rules with Generics
A generic class can participate in inheritance.
class Animal<T> {
    T value;
}

class Dog extends Animal {
}

Here, Dog inherits Animal<String>.

However:  List<Integer> and List<Number>
are not related by inheritance, even though Integer is a subclass of Number.
Therefore: List<Number> list = new ArrayList<Integer>();  Invalid

To achieve flexibility, wildcards can be used:
List list;
Java Collections Framework

The Java Collections Framework (JCF) provides interfaces and classes for storing and manipulating groups of objects.

List Interface: A List is an ordered collection that allows duplicate elements. Common implementations:
  • ArrayList
  • LinkedList
  • Vector
Example:
List <String> names = new ArrayList<>();
names.add("Ram");
names.add("Sita");
names.add("Ram");

Output can contain duplicate "Ram".

Set Interface

: A Set is a collection that does not allow duplicate elements. Common implementations:
  • HashSet
  • LinkedHashSet
  • TreeSet
Example:
Set<Integer> numbers = new HashSet<>();
numbers.add(10);
numbers.add(20);
numbers.add(10);
The duplicate 10 is ignored.
Map Interface
A Map stores data as key-value pairs. Example:
Map<Integer, String> students = new HashMap<>();
students.put(1, "Ram");
students.put(2, "Sita");
Here:
Integer --> key
String --> value
Keys are unique, while values can be duplicated.
Common implementations:
  • HashMap
  • LinkedHashMap
  • TreeMap

Queue Interface

A Queue is generally used to store elements in FIFO (First In, First Out) order. Common implementation:

Queue q = new LinkedList<>();
q.add("A");
q.add("B");
q.add("C");
Important methods:
Method Purpose
add() Adds an element
offer() Adds an element
poll() Removes and returns the front element
peek() Returns the front element without removing it

Deque Interface: Deque means Double-Ended Queue. Elements can be inserted and removed from both ends.
Deque<Integer> d = new ArrayDeque<>();
d.addFirst(10);
d.addLast(20);
Important methods:
  • addFirst()
  • addLast()
  • removeFirst()
  • removeLast()
  • peekFirst()
  • peekLast()
  • It can be used as both a queue and a stack.
  • Iterators and the Iterable Interface
An Iterator is used to traverse elements of a collection one by one.
List<String> names = new ArrayList<>();
names.add("Ram");
names.add("Sita");

Iterator<String> it = names.iterator();

while (it.hasNext()) {
    System.out.println(it.next());
}
Important methods:
  • hasNext()--> checks whether another element exists.
  • next() --> returns the next element.
  • remove() --> removes the current element.

The Iterable interface indicates that an object can be traversed using an iterator. Collections such as List and Set implement Iterable.

Enhanced for Loop with Collections

The enhanced for loop provides a simple way to traverse collections without explicitly creating an iterator.

List<String> names = new ArrayList<>();
names.add("Ram");
names.add("Sita");
names.add("Hari");

for (String name : names) {
    System.out.println(name);
}